home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
LIBRARY
/
SHDK_1
/
SHUTILPK.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1992-03-23
|
23KB
|
709 lines
{$O+,A-}
unit ShUtilPk;
{
ShUtilPk
A Utility Unit
by
Bill Madison
W. G. Madison and Associates, Ltd.
13819 Shavano Downs
P.O. Box 780956
San Antonio, TX 78278-0956
(512)492-2777
CIS 73240,342
Copyright 1991 Madison & Associates
All Rights Reserved
This file may be used and distributed only in accord-
ance with the provisions described on the title page of
the accompanying documentation file
SKYHAWK.DOC
}
Interface
Uses
TpCrt,
TpString,
TpDos,
Dos;
type
CharSet = set of char;
const
DelimSet : CharSet = [#0..#32];
{*****************************************************************}
{ !!!!!!!!!!!!!!!!! NEVER MODIFY THESE VARIABLES !!!!!!!!!!!!!!!!!}
{*****************************************************************}
Var
StartingMode : Byte;
{Initial video mode of the system (Mono, CO80, BW40, ...)}
StartingAttr : Byte;
{Initial video attribute of the system}
{*****************************************************************}
{*****************************************************************}
function BetwS(Lower, Item, Upper : LongInt) : boolean;
{Performs a SIGNED test of the condition that Lower <= Item <= Upper,
returning TRUE if and only if the condition is met. Lower, Item, and
Upper can be any combination of 1, 2, and 4-byte entities.}
{**********************************************************************}
function BetwU(Lower, Item, Upper : LongInt) : boolean;
{Performs an UNSIGNED test of the condition that Lower <= Item <= Upper,
returning TRUE if and only if the condition is met. Lower, Item, and
Upper can be any combination of 1, 2, and 4-byte entities.}
{**********************************************************************}
Function StarString(Pattern, Target : String) : Boolean;
{This function performs a generalization of the wildcard string
matching usually performed by DOS. A '*' wild card can be placed
anywhere within the pattern string, and will represent its usual
'zero or more of any characters'. Scanning will not be terminated
at that point, however, but will continue. Thus, '*B*EFG' will match
'ABCDEFG', but '*B*EGF' will not. Similarly, '*ABC*' will match, but
'*ABC' will not.}
{**********************************************************************}
Function WhoAmI : String;
{Returns the fully qualified path to the currently executing file.
*** DOS 3.x or above, ONLY ***}
{**********************************************************************}
function SearchEnvironment(Code : String) : String;
{Searches the environment space for "CODE" and returns the corresponding
string.}
{**********************************************************************}
Function LoWord(LI : LongInt) : Word;
{Returns the low order word of a LongInt.}
{**********************************************************************}
Function HiWord(LI : LongInt) : Word;
{Returns the high order word of a LongInt.}
{**********************************************************************}
Function LI(Ilo, Ihi : Word) : LongInt;
{Converts two Word vbls to a LongInt}
{**********************************************************************}
Function HEX(A : LongInt) : String;
{Converts a byte vbl into a string correspnoding to the hex value.}
{NOTE: The parameter A may be of any Integer type (ShortInt, Byte,
Integer, Word, or LongInt}
{HEX will return either a 2, 4, or 8 character string, depending on
whether the actual value of the parameter is representable as a
1 byte value (ShortInt, Byte)
2 byte value (Integer, Word)
4 byte value (LongInt)
Note that a negative value will always be returned as an 8 character
string.}
{**********************************************************************}
Function Pmod(x, modulus : LongInt) : LongInt;
{Returns the mod as a positive number, regardless of the sign of X.
Recall that, e.g., -1 is congruent to (modulus-1). Thus, for example,
Pmod(-2, 7) will return 5 as the function value.}
{**********************************************************************}
Procedure RepAll(S1, FS, SS : string; var S2 : string);
{In string S1 replace all occurrences of FS with SS, giving S2}
function RepAllF(S1, FS, SS : string) : string;
{**********************************************************************}
Procedure DelAll(S1, DS : string; var S2 : string);
{In string S1 delete all occurrences of DS, giving S2}
function DelAllF(S1, DS : string) : string;
{**********************************************************************}
function PosSet(A : CharSet; S : string) : byte;
{Returns the position of the first occurrance of any member of A in S}
{**********************************************************************}
Procedure GetNext(var S1, S2 : String);
{Extracts the next substring from S1 delimited by a member of DelimSet
and returns it in S2. S1 is returned with the sub-string stripped off.
If S1 is empty on entry, both S1 and S2 will be empty on return.}
function GetNextF(var S1 : string) : string;
{**********************************************************************}
function UniqueFileName(Path : string; AddExt : boolean) : string;
{Returns a file name which will be unique in the directory specified
by PATH. On return, the file name will be appended to PATH. If AddExt
is TRUE, an extension of .$$$ will be appended, else only the file name
will be returned.}
{**********************************************************************}
Implementation
{------------}
var
Regs : Registers;
XY : WindowCoordinates;
{**********************************************************}
function BetwS(Lower, Item, Upper : LongInt) : boolean;
{Performs a SIGNED test of the condition that Lower <= Item <= Upper,
returning TRUE if and only if the condition is met. Lower, Item, and
Upper can be any combination of 1, 2, and 4-byte entities.}
begin
BetwS := (Item >= Lower) and (Item <= Upper);
end;
{**********************************************************}
function BetwU(Lower, Item, Upper : LongInt) : boolean;
{Performs an UNSIGNED test of the condition that Lower <= Item <= Upper,
returning TRUE if and only if the condition is met. Lower, Item, and
Upper can be any combination of 1, 2, and 4-byte entities.}
const
{In the following table, columns represent hi-word states,
rows represent lo-word states.
1. a < b, b < c 4. a = b, b < c 7. a > b, b < c
2. b = c 5. b = c 8. b = c
3. b > c 6. b > c 9. b > c }
ST : array[1..9,1..9] of boolean =
(( true, true, false, true, true, false, false, false, false),
( true, true, false, true, true, false, false, false, false),
( true, false, false, true, false, false, false, false, false),
( true, true, false, true, true, false, false, false, false),
( true, true, false, true, true, false, false, false, false),
( true, false, false, true, false, false, false, false, false),
( true, true, false, false, false, false, false, false, false),
( true, true, false, false, false, false, false, false, false),
( true, false, false, false, false, false, false, false, false));
type
WO = ( HW, LW );
X = record
case byte of
1 : (L : LongInt);
2 : (W : array[ WO ] of word);
end;
LT = 1..3;
var
HiState,
LoState : byte;
function LEG(A, B : word) : LT;
{Returns 1, 2, 3 as A is <, =, > B}
begin
if A < B then
LEG := 1
else if A = B then
LEG := 2
else
LEG := 3;
end;
begin
HiState := (3 * LEG(X(Lower).W[HW], X(Item).W[HW]) - 2) +
(LEG(X(Item).W[HW], X(Upper).W[HW]) - 1);
LoState := (3 * LEG(X(Lower).W[LW], X(Item).W[LW]) - 2) +
(LEG(X(Item).W[LW], X(Upper).W[LW]) - 1);
BetwU := ST[HiState, LoState];
end;
{**********************************************************}
Function StarString;
{StarString is a Boolean function which returns True if a pattern
string possibly containing one or more '*' wild cards matches a
target. It works by repeatedly extracting maximum length sub-
strings not containing a * from Pattern, determining if that sub-
string exists in Target, and, if so, deleting from Target the first
character through the end of the partial pattern. A final test is
made on the residual portion of each to determine the final truth
value of the function. Character wild cards ('?') are handled by
substituting characters 1-for-1 from the target string into the
earliest possible match and proceeding as if they were non-existant.
The function will terminate as soon as the truth value can be
determined, so that no time is wasted in execution.}
var
Index : Byte;
TrialB : String;
procedure ReplQ(var Pattern1 : String; Target1 : String);
{Replaces all occurrences of '?' in Pattern1 with the corresponding
character from Target1. If Target1[0] < Pattern1[0], any '?' occurring
in the tail will not be effected.}
var
T1 : Byte;
begin
T1 := Pos('?', Pattern1);
While (T1 <> 0) and (T1 <= Byte(Pattern1[0])) do begin
Pattern1[T1] := Target1[T1];
T1 := Pos('?', Pattern1);
end;
end; {ReplQ}
procedure Split(Instr : String; Ch : Char; var Before, After : String;
var Index : Byte);
{Splits Instr on the first occurrence of the character Ch. The products
of the split are returned in Before and After. Ch itself is discarded.
Index returns the character position in Instr at which the split
occurred. (0 means no split)}
begin
Index := Pos(Ch, Instr);
Before := Copy(Instr, 1, Index - 1);
Delete(Instr, 1, Index);
After := Instr;
end; {Split}
procedure CountOccur(PatStr, InStr : String; var Count : Byte);
{Counts the number of occurrences of PatStr in Instr and returns the
count in Count}
var
T1 : Byte;
begin
Count := 0;
T1 := Pos(PatStr, InStr);
While T1 <> 0 do begin
Inc(Count);
Delete(Instr, 1, T1);
T1 := Pos(PatStr, Instr);
end;
end; {CountOccur}
procedure BuildMatch(var Pattern1, Target1 : String; var Index1 : Byte);
{If possible, constructs the version of Pattern1 which matches the
earliest substring of Target1 by eliminating character wild cards.
The position is returned in Index1}
var
Pat1 : String;
T1, {Pointer within Target1 to start of trial match }
T2, {FOR loop index for character replacement }
T3, {Number of character wild cards in Pat1 }
T4 : Byte; {Position of the T3th character wild card }
begin
If Pattern1 = '' then exit;
If Pos('?', Pattern1) = 0 then begin
Index1 := Pos(Pattern1, Target1);
exit;
end;
T1 := 0;
Pat1 := Pattern1;
CountOccur('?', Pat1, T3);
Index1 := Pos(Pat1, Target1);
While ((T1 + Byte(Pat1[0])) <= Byte(Target1[0])) and
(Index1 = 0) do begin
For T2 := 1 to T3 do begin
T4 := Pos('?',Pat1);
Pat1[T4] := Target1[T1+T4];
end; {For}
Index1 := Pos(Pat1, Target1);
If Index1 = 0 then
Pat1 := Pattern1
else
Pattern1 := Pat1;
Inc(T1);
end; {While}
end; {BuildMatch}
begin {StarString}
{First, take care of all the special cases}
While Pos('**', Pattern) <> 0 do
Delete(Pattern, Pos('**', Pattern), 1);
If (Byte(Pattern[0]) = 0) or {No pattern string }
(Byte( Target[0]) = 0) then begin {or no target string}
StarString := False;
Exit;
end;
If Pattern[1] = '?' then
Pattern[1] := Target[1];
If Pos('*', Pattern) = 0 then begin {No wild cards, so }
ReplQ(Pattern, Target); {Quick result known}
StarString := (Pattern = Target);
Exit;
end;
Split(Pattern, '*', TrialB, Pattern, Index);
BuildMatch(TrialB, Target, Index);
If Index <> 1 then begin {No match possible }
StarString := False;
exit;
end;
{End of special cases. Proceed with normal processing}
Pattern := TrialB + '*' + Pattern; {Possible match, so }
{reconstruct Pattern }
{and proceed }
While (Pos('*', Pattern) <> 0) do begin {Still more wild cards}
Split(Pattern, '*', TrialB, Pattern, Index);
{Disect the pattern }
{TrialB now contains that portion to the left of the wildcard,
and Pattern contains what was to the right. The wild card
itself has been discarded.}
{From TrialB build the best possible match to Target, getting
rid of character wild cards. Put the expanded string back into
TrialB for further processing.}
BuildMatch(TrialB, Target, Index); {Try to find a match }
{ and set the Index }
If Index = 0 then begin {No match is possible }
StarString := False;
exit;
end
else begin {Still possible match}
Delete(Target, 1, Index + Byte(TrialB[0]) - 1);
end; {Strip off past the }
end; {While} { last left pattern }
{ and try again }
If Byte(Pattern[0]) = 0 then {'*' as last character of Pattern}
StarString := True { so we know there is a match. }
else begin { Make sure we are looking at *last* occurrance }
{ of Pattern in Target }
Index := Pos(Pattern, Target);
TrialB := Target; { Save the current target }
While Index <> 0 do begin
Delete(Target, 1, Index + Byte(Pattern[0]) - 1);
{ Delete through end of Pattern }
Index := Pos(Pattern, Target);
If Index <> 0 then TrialB := Target; { Save the new target }
end;
{ TrialB now contains the maximum length substring of Target }
{ which contains the *last* occurrance of Pattern. }
BuildMatch(Pattern, TrialB, Index);
If Index = 0 then
StarString := False
else
StarString := ((Index + Byte(Pattern[0]) - 1) = Byte(TrialB[0]));
end;
end; {Function StarString}
{***************************************************************}
function WhoAmI;
var
s, o : integer;
c : string;
begin
s := memw[PrefixSeg:$2c]; {the segment address of the start of }
o := 0; { the environment area at PrefixSeg:$2c}
while memw[s:o] <> 0 do {search for end of environment }
o := succ(o); { which is marked by two 0 bytes }
o := o + 4; {skip across word count }
c := '';
repeat
c := c + chr(mem[s:o]); {transfer fully qualified path }
o := succ(o); { as a legitimate TurboPASCAL string}
until mem[s:o] = 0;
WhoAmI := c;
end;
{**********************************************************************}
function searchenvironment;
var
x,y : integer;
cs : string;
begin
x := memw[prefixseg:$2C];
y := 0;
while memw[x:y] <> 0 do begin
if chr(mem[x:y]) = code[1] then begin
cs := '';
repeat {copy up to the '='}
cs := cs + chr(mem[x:y]);
y := y + 1
until chr(mem[x:y]) = '=';
if cs = code then begin {got a match, so}
y := y + 1; {space across the '='}
cs := '';
repeat {and copy what's on the other side}
cs := cs + chr(mem[x:y]);
y := y + 1
until mem[x:y] = 0;
searchenvironment := cs; {and that's the function value..}
exit {so set it and bail out}
end {if cs = code}
end {chr(mem[x:y]) = code[1]}
else {no match, so}
repeat {just find the end of the string}
y := y + 1
until mem[x:y] = 0;
y := y + 1; {space across string delimiter}
end; {while}
searchenvironment := '';
end; {of searchenvironment}
{**********************************************************}
Function LoWord;
type
XT = array[1..2] of Word;
var
X : XT absolute LI;
begin
LoWord := X[1];
end;
{**********************************************************************}
Function HiWord;
type
XT = array[1..2] of Word;
var
X : XT absolute LI;
begin
HiWord := X[2];
end;
{**********************************************************************}
Function LI;
{Converts two Word vbls to a LongInt}
type
LItype = record
case Integer of
1 : (IT : array[1..2] of Integer);
2 : (LIT: LongInt);
end;
var
X : LItype;
begin
X.IT[1] := Ilo;
X.IT[2] := Ihi;
LI := X.LIT;
end;
{**********************************************************************}
Function HEX;
Type
HexByte = record
case Byte of
1 : (LI : LongInt);
2 : (BY : array[0..3] of Byte);
3 : (Ts : array[0..1] of Word);
end;
Const
B : Array[0..15] of Char =
('0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F');
Var
S1 : String;
T1,
T2 : Byte;
HB : HexByte absolute A;
Begin
Case HB.Ts[1] of
0 : begin
T2 := 1; {At most 2 byte vbl}
Case HB.BY[1] of
0 : T2 := 0; {It's a Byte}
end;
end;
else T2 := 3;
end;
S1 := '';
For T1 := T2 downto 0 do
S1 := S1 + B[HB.BY[T1] shr 4] + B[HB.BY[T1] and $0F];
HEX := S1;
end;
{**********************************************************************}
function Pmod;
begin
Pmod := ((x mod modulus) + modulus) mod modulus;
end;
{**********************************************************}
Procedure RepAll(S1, FS, SS : string; var S2 : string);
{In string S1 replace all occurrences of FS with SS}
var
T1 : Integer;
S3 : string;
begin
S2 := '';
while Pos(FS, S1) <> 0 do begin
T1 := Pos(FS, S1);
S2 := S2 + copy(S1, 1, pred(T1)) + SS;
delete(S1, 1, pred(T1) + Length(FS));
end; {while}
S2 := S2 + S1;
end; {RepAll}
function RepAllF(S1, FS, SS : string) : string;
var
S2 : string;
begin
RepAll(S1, FS, SS, S2);
RepAllF := S2;
end; {RepAllF}
{**********************************************************}
Procedure DelAll(S1, DS : string; var S2 : string);
{In string S1 delete all occurrences of DS}
begin
RepAll(S1, DS, '', S2);
end;
function DelAllF(S1, DS : string) : string;
begin
DelAllF := RepAllF(S1, DS, '');
end; {DelAllF}
{**********************************************************}
function PosSet(A : CharSet; S : string) : byte;
var
T1 : byte;
begin
T1 := 1;
while (not (S[T1] in A)) and (T1 < Length(S)) do
inc(T1);
if S[T1] in A then
PosSet := T1
else
PosSet := 0;
end; {PosSet}
function TrimLeadSet(S : string; CS : CharSet) : string;
var
L : byte;
begin
L := 1;
while (S[L] in CS) and (L <= byte(S[0])) do
inc(L);
if L = 0 then
TrimLeadSet := ''
else
TrimLeadSet := Copy(S, L, 255);
end; {TrimLeadSet}
function TrimTrailSet(S : string; CS : CharSet) : string;
begin
while (S[byte(S[0])] in CS) and (byte(S[0]) > 0) do
dec(S[0]);
TrimTrailSet := S;
end; {TrimTrailSet}
function TrimSet(S : string; CS : CharSet) : string;
begin
TrimSet := TrimTrailSet(TrimLeadSet(S, CS), CS);
end; {TrimSet}
Procedure GetNext(var S1, S2 : String);
{Extracts the next space-delimited string from S1 and returns it
in S2. S1 is returned with the sub-string stripped off.
If S1 is empty on entry, both S1 and S2 will be empty on return.}
var
T1 : Integer;
begin {GetNext}
If Length(S1) = 0 then begin
S2[0] := chr(0);
Exit
end;
S1 := TrimSet(S1, DelimSet); {Strip leading and trailing blanks}
If Length(S1) = 0 then
S2[0] := chr(0)
else
If PosSet(DelimSet, S1) <> 0 then begin
T1 := PosSet(DelimSet, S1);
S2 := Copy(S1, 1, Pred(T1));
S1 := Copy(S1, T1, Length(S1) - Pred(T1));
end
else begin
S2 := S1;
S1 := '';
end;
end; {GetNext}
function GetNextF(var S1 : string) : string;
var
S2 : string;
begin
GetNext(S1, S2);
GetNextF := S2;
end; {GetNextF}
{**********************************************************}
function UniqueFileName(Path : string; AddExt : boolean) : string;
var
FN : record
case integer of
1 : (LI : LongInt);
2 : (WD : array[1..2] of word);
end;
R : Registers;
S : string;
begin
R.AH := $2C;
MsDos(R);
FN.WD[1] := R.CX;
FN.WD[2] := R.DX;
repeat
Inc(FN.LI);
S := Path + HexL(FN.LI);
if AddExt then S := S + '.$$$';
until not ExistFile(S);
UniqueFileName := S
end;
{**********************************************************}
begin {Initialization section}
StartingMode := Mem[0:$449];
With Regs do begin
AH := 8;
Intr( $10, Regs );
StartingAttr := AH;
end;
end.